package com.meevle.business;

import java.io.File;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.red5.core.ApplicationSettings;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;

import com.meevle.dao.SetDAO;
import com.meevle.dao.SlotCommentDAO;
import com.meevle.dao.SlotDAO;
import com.meevle.dao.UserDAO;
import com.meevle.utilities.DaoToVoAdapter;
import com.meevle.utilities.RegexController;
import com.meevle.utilities.VoToDAoAdapter;
import com.meevle.vo.SetVO;
import com.meevle.vo.SlotCommentVO;
import com.meevle.vo.SlotVO;
import com.meevle.vo.UserVO;

public class SlotDelegate {

        private static Logger log = Red5LoggerFactory.getLogger(
                        SlotDelegate.class, "Meevle");

        /**
         * Get all the projects a certain track has featured in
         *
         * @param voTrack
         *            the trackobject
         * @return
         * @throws IllegalArgumentException
         *             when there was something wrong with the parameter, read the
         *             exception message
         * @throws Exception
         *             when something else was wrong
         */
        public List<SetVO> getSets(SlotVO voSlot)
                        throws IllegalArgumentException, Exception {
                try {
                        RegexController.getInstance().checkUsername(
                                        voSlot.getOwner().getUsername());
                        RegexController.getInstance().checkSlotname(voSlot.getName());
                } catch (Exception e) {
                        throw e;
                }

                List<SetVO> sets = new ArrayList<SetVO>();

                List<SetDAO> projectDaos;
                try {
                        // projectDaos = SlotDAO.getSetsBySlot(voSlot);
                        SlotDAO t = SlotDAO.getSlot(voSlot);
                        projectDaos = t.getSets();
                } catch (IllegalArgumentException e) {
                        throw e;
                }

                try {
                        for (SetDAO projectDao : projectDaos)
                                sets.add(DaoToVoAdapter.getInstance()
                                                .getSetFromSetDAO(projectDao));
                } catch (NullPointerException e) {
                        log.error(e.getMessage());
                        throw e;
                }

                return sets;
        }

        /**
         * Adds the track to the database. The code checks if:
         *
         * - the user, the genre, the instrument exist in the database
         *
         * @param trackVo
         *            the track that the client wants to add to the database
         * @return True if creation succeeded, false if it didn't
         * @throws IllegalArgumentException
         *             When something was wrong with the parameters
         * @throws Exception
         *             If something went wrong with the parameters
         */
        public static boolean createSlot(UserVO user, SlotVO trackVo)
                        throws IllegalArgumentException, Exception {
                try {
                        RegexController.getInstance().checkUsername(user.getUsername());
                        RegexController.getInstance().checkSlotname(trackVo.getName());
                } catch (IllegalArgumentException e) {
                        throw e;
                }

                boolean ret = false;
                File sourcePath, destinationDirectory = null;
                String newFilename = null;
                List<Object> objects = null;

                // controleren of track bij die user al bestaat of nog niet?
                try {
                        if (UserDelegate.isUserOwnerOfSlot(DaoToVoAdapter.getInstance()
                                        .getUserFromUserDAO((UserDAO) objects.get(2)), trackVo))
                                throw new IllegalArgumentException(
                                                "The user already has a track with the name "
                                                                + trackVo.getName());

                } catch (Exception e) {
                        // throw e;
                        ;
                }
                System.out.println("############  Testttttttt");
                // Check for errors
                try {
                        objects = check(user, trackVo);
                } catch (IllegalArgumentException ill) {
                        throw ill;
                } catch (Exception e) {
                        throw e;
                }

                sourcePath = new File(ApplicationSettings.getInstance()
                                .getContextFullPath()
                                + ApplicationSettings.getInstance().getUserTempPath(
                                                user.getUsername())
                                + File.separator
                                + ApplicationSettings.getInstance().getTempStreamFilename()
                                + ".mp3");

                if (sourcePath.exists()) {
                        newFilename = String.valueOf(System.currentTimeMillis()) + ".mp3";
                        destinationDirectory = new File(ApplicationSettings.getInstance()
                                        .getContextFullPath()
                                        + ApplicationSettings.getInstance().getUserTracksPath(
                                                        user.getUsername()));

                        if (moveFile(sourcePath, destinationDirectory, newFilename)) {
                                try {
                                        if (persistSlot(trackVo, destinationDirectory,
                                                        newFilename, objects)) {
                                                UserDAO.addSlotToUser(trackVo.getOwner(), trackVo);
                                                // RestrictedMethods.getInstance().addSlotToInstrument(trackVo.getInstrument(),
                                                // trackVo);
                                                // RestrictedMethods.getInstance().addSlotToUser(user,
                                                // trackVo);
                                                ret = true;
                                        } else
                                                System.out
                                                                .println("\nSlotDelegate: createSlot : Persisten van track naar DB is niet gelukt");
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                        }
                }

                else
                        log.error("SourcePath does not exist");

                return ret;
        }

        /**
        *
        * @param slotVo
        *            The track of which the date should be persisted
        * @param destinationDirectory
        *            The destinationdirectory of the persisted track
        * @param newFilename
        *            The filename of the new track under the destinationdirectory
        * @param objects
        *            <code>List</code> of Objects that contains a GenreDAO, an
        *            InstrumentDAO and a UserDAO object
        * @return True if persisting succeeded
        * @throws Exception
        *             if something went wrong with the persisting
        */
       public static boolean persistSlot(SlotVO slotVo)
                       throws Exception {
               boolean ret = false;

               SlotDAO slot;
               slot = new SlotDAO();
               slot.setOwner(UserDAO.getUser(slotVo.getOwner()));
               slot.setName(slotVo.getName());
               slot.setDirectory(slotVo.getDirectory());
               slot.setFilename(slotVo.getFilename());
               slot.setSlotIndex(slotVo.getIndex());
               slot.setTimeCreated(new Timestamp(System.currentTimeMillis()));


               try {
                       SlotDAO.persist(slot);
               } catch (IllegalArgumentException ill) {
                       log.error("Adding a new track to the database failed because:\n"
                                       + ill.getMessage());
                       throw ill;
               }

               catch (Exception e) {
                       log.error("Adding a new track to the database failed because:\n");
                       e.getMessage();
                       throw e;
               }
               ret = true;
               return ret;
       }
        
        /**
         *
         * @param trackVo
         *            The track of which the date should be persisted
         * @param destinationDirectory
         *            The destinationdirectory of the persisted track
         * @param newFilename
         *            The filename of the new track under the destinationdirectory
         * @param objects
         *            <code>List</code> of Objects that contains a GenreDAO, an
         *            InstrumentDAO and a UserDAO object
         * @return True if persisting succeeded
         * @throws Exception
         *             if something went wrong with the persisting
         */
        private static boolean persistSlot(SlotVO trackVo,
                        File destinationDirectory, String newFilename, List<Object> objects)
                        throws Exception {
                boolean ret = false;

                SlotDAO track;
                track = new SlotDAO();
                System.out.println("\n" + objects);
                track.setOwner((UserDAO) objects.get(2));
                track.setName(trackVo.getName());
                trackVo.setDirectory(destinationDirectory.toString());
                trackVo.setFilename(newFilename);


                try {
                        SlotDAO.persist(track);
                } catch (IllegalArgumentException ill) {
                        log.error("Adding a new track to the database failed because:\n"
                                        + ill.getMessage());
                        throw ill;
                }

                catch (Exception e) {
                        log.error("Adding a new track to the database failed because:\n");
                        e.getMessage();
                        throw e;
                }
                ret = true;
                return ret;
        }


        /**
         * Checks if anything is wrong with the user or with the trackVo. More in
         * detail: <br />
         * <ul>
         * <li>does the user exist in the database;</li>
         * <li>is there anything that's null;</li>
         * <li>do the genre and the instrument of the track exist;</li>
         * <li>etc.</li>
         * </ul>
         *
         * @param user
         *            The user that's trying to undertake the action (e.g. inserting
         *            a track)
         * @param trackVo
         *            The track that's subject of the action (e.g. the track being
         *            inserted)
         * @return A <code>List<Object></code> that contains a <code>GenreDAO</code>
         *         object, an <code>InstrumentDAO</code> object and a
         *         <code>UserDAO</code> object
         * @throws IllegalArgumentException
         *             if something was wrong with the parameters. The
         *             Exceptionmessage should say enough.
         * @throws Exception
         *             If something else went wrong
         */
        public static List<Object> check(UserVO user, SlotVO trackVo)
                        throws IllegalArgumentException, Exception {
                try {
                        RegexController.getInstance().checkUsername(user.getUsername());
                        RegexController.getInstance().checkSlotname(trackVo.getName());
                } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                        throw e;
                }

                List<Object> objects = null;

                try {
                        objects = checkParameters(user, trackVo);
                } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                        throw e;
                } catch (NullPointerException e) {
                        e.printStackTrace();
                        throw e;
                }

                // is the owner of the track the same one creating it?
                if (!trackVo.getOwner().equals(user))
                        throw new IllegalArgumentException(
                                        "The owner of the track and the user creating the track are not the same");

                return objects;
        }

        /**
         * Checks both the parameters of both the <code>UserVO</code> object and the
         * <code>SlotVO</code> object and returns a <code>List</code> of objects
         * containing respectively a GenreDAO object, an InstrumentDAO object and a
         * UserDAO object
         *
         * @param userVo
         *            The user trying to perform an action (e.g. persisting a track)
         * @param trackVo
         *            The track undergoing the action (e.g. being persisted)
         * @return <code>List<Object></code>
         * @throws IllegalArgumentException
         *             If something was wrong with the parameters: the user does not
         *             exist, the genre of the track does noet exist, the instrument
         *             does not exist, ... The Exceptionmessage should say what's
         *             wrong
         * @throws NullPointerException
         *             If userVo or trackVo are null
         * @throws Exception
         *             If something went wrong during the accessing of the DB
         */
        private static List<Object> checkParameters(UserVO userVo, SlotVO trackVo)
                        throws IllegalArgumentException, NullPointerException, Exception {
                List<Object> objects;
                List<String> erroneousRequiredParameters;

                if (userVo == null || trackVo == null)
                        throw new NullPointerException(
                                        "Nor the User, nor the track can be null");

                try {
                        objects = checkSlotParameters(trackVo);
                } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                        throw e;
                } catch (Exception e) {
                        throw e;
                }

                erroneousRequiredParameters = (List<String>) objects.get(1);
                if (erroneousRequiredParameters.size() > 0) {
                        StringBuffer buf = new StringBuffer();
                        ;
                        for (String str : erroneousRequiredParameters)
                                buf.append(str + "\n");
                        throw new IllegalArgumentException(buf.toString());
                }

                return objects.subList(0, 0);
        }

        /**
         * Get all the tracks from the database
         *
         * @return a list of <code>SlotVO</code>objects
         */
        public static List<SlotVO> getAllSlots() {
                List<SlotVO> ret = new ArrayList<SlotVO>();
                List<SlotDAO> trackDaos = new ArrayList<SlotDAO>();
                try {
                        trackDaos = SlotDAO.getAll();
                } catch (Exception e) {
                        ;
                }

                for (SlotDAO trackDao : trackDaos)
                        ret
                                        .add(DaoToVoAdapter.getInstance().getSlotFromSlotDAO(
                                                        trackDao));
                return ret;
        }

        /**
         * Checks if the required parameters for a track are there. It DOES NOT
         * chech if such a track already exists.
         *
         * @param trackVo
         * @return a <code>List<String></code> that contains the errormessages
         * @return a <code>List<String></code> of <code>Object</code> that contains
         *         a <code>GenreDAO</code>object, a <code>UserDAO</code>object and a
         *         <code>List<String></code> which contains the error messages, if
         *         any
         * @throws IllegalArgumentException
         *             if one of the paramaters does not exist (genre, instrument,
         *             user)
         * @throws Exception
         *             If went wrong during the accessing of the DB
         */
        private static List<Object> checkSlotParameters(SlotVO trackVo)
                        throws IllegalArgumentException, Exception {
                List<Object> ret = new ArrayList<Object>(2);
                List<String> messages = new ArrayList<String>(1);

                UserDAO u;

                try {
                        u = UserDAO.getUser(trackVo.getOwner());
                } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                        throw e;
                } catch (Exception e) {
                        throw e;
                }

           
                if (trackVo.getName() == null || trackVo.getName().length() == 0)
                        messages.add("The name of the track must be set");

               
                ret.add(u);
                ret.add(messages);

                return ret;
        }

        /**
         * Move a file from sourcepath to destinationpath
         *
         * @param user
         *            The owner of the track
         * @return true if it worked and false if it didn't
         */
        private static boolean moveFile(File sourcePath, File destinationDirectory,
                        String newFilename) {
                boolean ret;
                // MOVE THE FILE
                ret = sourcePath.renameTo(new File(destinationDirectory.toString()
                                + File.separator + newFilename));
                return ret;
        }


        /**
         * Get a fully updated <code>SlotVO</code> object filled with the latest
         * properties from the database
         *
         * @param track
         * @return A fully updated SlotVo-object or null if track was null.
         * @throws IllegalArgumentException
         *             if something was wrong with the track parameter
         * @throws Exception
         *             If somethinf went wrong during the accessing of the DB
         */
        public static SlotVO getSlot(SlotVO track)
                        throws IllegalArgumentException, Exception {
                SlotVO tr = null;


                try {
                        RegexController.getInstance().checkSlotname(track.getName());
                        RegexController.getInstance().checkUsername(
                                        track.getOwner().getUsername());
                        tr = DaoToVoAdapter.getInstance().getSlotFromSlotDAO(
                                        SlotDAO.getSlot(track));
                } catch (NullPointerException e) {
                        ;
                } catch (IllegalArgumentException e) {
                        throw e;
                } catch (Exception e) {
                        throw e;
                }

                return tr;
        }

        /**
         * Get all tracks with a certain name
         *
         * @param trackname
         *            The name of the tracks
         * @return A <code>List</code> of all tracks with that particular name
         * @throws HibernateException
         *             When something went wrong during the database access
         * @throws Exception
         *             When something else than the databaseaccess went wrong
         */
        public static List<SlotVO> getAllSlotsByName(String trackname)
                        throws HibernateException, Exception {
                try {
                        RegexController.getInstance().checkSlotname(trackname);
                } catch (IllegalArgumentException e) {
                        throw e;
                }
                List<SlotVO> tracks = new ArrayList<SlotVO>();
                List<SlotDAO> trackDaos;
                try {
                        trackDaos = SlotDAO.getAllSlotsByName(trackname);
                } catch (HibernateException e) {
                        throw e;
                } catch (Exception e) {
                        throw e;
                }

                for (SlotDAO trackDao : trackDaos)
                        tracks.add(DaoToVoAdapter.getInstance().getSlotFromSlotDAO(
                                        trackDao));
                return tracks;
        }

        /**
         * Get a subset of all the tracks
         *
         * @param startIndex
         *            Index of the first track
         * @param numberOfItems
         *            Number of tracks that being returned
         * @return A <code>List</code> of <code>SlotDAO</code> objects
         * @throws HibernateException
         *             When something went wrong during the database access
         * @throws Exception
         *             When something else than the databaseaccess went wrong
         */
        public static List<SlotVO> getAllSlotsFromTo(int startIndex,
                        int numberOfItems, String howToOrder) throws HibernateException,
                        Exception {

                List<SlotVO> tracks = new ArrayList<SlotVO>();

                List<SlotDAO> trackDaos;
                try {
                        trackDaos = SlotDAO.getAllSlotsFromTo(startIndex, numberOfItems,
                                        howToOrder);
                } catch (HibernateException e) {
                        throw e;
                } catch (Exception e) {
                        throw e;
                }

                for (SlotDAO trackDao : trackDaos)
                        tracks.add(DaoToVoAdapter.getInstance().getSlotFromSlotDAO(
                                        trackDao));

                return tracks;
        }

        /**
         * Update a track with new values
         *
         * @param oldSlot
         * @param newSlot
         * @throws IllegalArgumentException
         *             If there was something wrong with the provided parameters
         * @throws Exception
         *             If there went something wrong during the DB access
         */
        public static void update(SlotVO oldSlot, SlotVO newSlot)
                        throws IllegalArgumentException, Exception {
                try {
                        RegexController.getInstance().checkSlotname(oldSlot.getName());
                        RegexController.getInstance().checkSlotname(newSlot.getName());
                        RegexController.getInstance().checkUsername(
                                        oldSlot.getOwner().getUsername());
                        RegexController.getInstance().checkUsername(
                                        newSlot.getOwner().getUsername());

                        SlotDAO.update(oldSlot, newSlot);
                } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                        throw e;
                } catch (Exception e) {
                        e.printStackTrace();
                        throw e;
                }
        }

        /**
         * Add a new comment to a Slot.  Note that the comment itself is not checked against a regex. Instead, it's processed by
         * a BBCode generator.
         *
         * @param commentVo
         *            The comment on the Slot
         * @return True if the comment has successfully been added to the track
         * @throws IllegalArgumentException
         *             If The commentVo.Slot or commentVO.user don't exist
         * @throws Exception
         *             If something went wrong during the DB access
         */
        public static boolean addCommentToSlot(SlotCommentVO commentVo)throws IllegalArgumentException, Exception {
        //TODO some kind control of the input to avoid SQL en JS injection http://nexodyne.com/showthread.php?t=14736
                //Solution = BBCode processor? //TODO test!!
                boolean ret = false;
                if (commentVo.getComment() != null && !commentVo.getComment().trim().equals("") 
                                && commentVo.getSlot() != null && commentVo.getAuthor() != null && commentVo.getTimeStamp() != null) {
                        try {
                                RegexController.getInstance().checkSlotname(
                                                commentVo.getSlot().getName());
                                RegexController.getInstance().checkUsername(
                                                commentVo.getAuthor().getUsername());
                                
                                SlotDAO trackDao = SlotDAO.getSlot(commentVo.getSlot());
                                SlotCommentDAO commentDao = VoToDAoAdapter.getInstance()
                                                .getSlotCommentDAOFromSlotCommentVO(commentVo, false);

                                if (!trackDao.getComments().contains(commentDao)) {
                                        trackDao.getComments().add(commentDao);
                                        PersistenceManagerImpl.merge(trackDao);
                                        PersistenceManagerImpl.addCommentToUser(commentVo.getAuthor(), commentVo);
                                        ret = true;
                                }
                        } catch (IllegalArgumentException e) {
                                e.printStackTrace();
                                throw e;
                        } catch (Exception e) {
                                throw e;
                        }
                }
                else throw new IllegalArgumentException("The comment ("+commentVo.getComment()+") could not be added to the track." +
                                "\nBe sure to fill in all the fields: ");
                return ret;

        }

        /**
         * Get the comments related to this track
         * @param trackVo The Slot
         * @return
         * @throws IllegalArgumentException If there's something wrong with trackVo.Name or with trackVo.User
         * @throws Exception
         */
        public static List<SlotCommentVO> getSlotComments(SlotVO trackVo)throws IllegalArgumentException, Exception
        {
                List<SlotCommentVO> comments = new ArrayList<SlotCommentVO>(0);
               
                try {
//                        RegexController.getInstance().checkSlotname(trackVo.getName());
//                        RegexController.getInstance().checkUsername(trackVo.getOwner().getUsername());
                       
                       
                        List<SlotCommentDAO> commentsDao = SlotDAO.getSlot(trackVo).getComments();
                       
                        for(SlotCommentDAO commentDao : commentsDao)
                                comments.add(DaoToVoAdapter.getInstance().getSlotCommentVOFromSlotCommentDAO(commentDao));


                } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                        throw e;
                } catch (NullPointerException e) {
                        e.printStackTrace();
                        throw new IllegalArgumentException("The track cannot be null");
                } catch (Exception e) {
                        e.printStackTrace();
                        throw e;
                }
               
                return comments;
        }
}
